#include <sys/ioctl.h>
#include "recordModule.h"
#include "hydrology.h"
#include <devnode.h>

#include <alsa/asoundlib.h>
#include <fdk-aac/aacenc_lib.h>

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <alsa/asoundlib.h>
#include <fdk-aac/aacenc_lib.h>
#include <pthread.h>

#define CARD_NAME	"default"

static snd_pcm_t *capture_handle = NULL;
static int record_thread_start = 0;

static pthread_t audio_record_thread = 0;

/* 录音参数 */
static int frames_count = 0;
static unsigned int rate = 8000;
static unsigned int channels = 1;
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; // 采样位数：16bit、LE格式

/* aac编码器 */
static HANDLE_AACENCODER aacEncHandle = NULL;
static AACENC_InfoStruct aacEncInfoSt = {0};
static AACENC_ERROR aacErrNum = AACENC_OK;

/* 编码相关参数 */
static unsigned int u32PcmInBufBytes = 0;
static int u32AacOutBufMaxBytes = 0;
static unsigned char *pu8PcmInBuf	 = NULL;
static unsigned char *pu8AacEncBuf  = NULL;

static int inIdentifier;
static int outIdentifier;
static int inElsize; // 参考aacenc_lib.h:260示例
static int outElsize;
static int s32ReadPcmBytes;

/* aac编码一帧数据用到的参数 */
static AACENC_BufDesc inPcmBufDesc = {0};
static AACENC_BufDesc outAacBufDesc = {0};
static AACENC_InArgs inArgs = {0};
static AACENC_OutArgs outArgs = {0};

static char g_devSn[32] = {0};

int aacEncEncode_init(void)
{
	/* 编码器 PCM参数 */
	unsigned int u32PcmSampleRate = rate;			// 采样率 8000
	unsigned int u32PcmSampleBits = 16;				// 采样位数 16
	unsigned int u32PcmChannels = channels;			// 声道数	1

	/* AAC编码 1/8：打开编码器，传出编码器句柄 */
	aacErrNum = aacEncOpen(&aacEncHandle, 0, u32PcmChannels);
	if(aacErrNum != AACENC_OK)
	{
		DEBUG("Open aac encoder error!\n");
		return -1;
	}

	/* AAC编码 2/8：配置/初始化编码器 */
	// 配置编码器 a/b：设置参数
	aacErrNum  = aacEncoder_SetParam(aacEncHandle, AACENC_AOT, AOT_AAC_LC); 	// Audio object type, 选择输出规格
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_SBR_MODE, 1); 		// Spectral Band Replication，是否使能SBR技术，-1:自动配置（默认） 0:关闭 1:开启
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_SAMPLERATE, u32PcmSampleRate); // Audio input data sampling rate
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_CHANNELMODE, (u32PcmChannels == 1) ? MODE_1 : MODE_2); // 声道模式，还有多种模式，这里只列出2种
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_CHANNELORDER, 1); 	// 输入音频数据通道排序方案，0: MPEG频道排序（默认） 1: WAVE文件格式通道排序
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_BITRATEMODE, 1); 		// 比特率模式，0:CBR  1~5:VBR（数值越大动态码率越高）
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_BITRATE, 128000); 	// 设置比特率大小，只有AACENC_BITRATEMODE设置为静态码率CBR时生效，VBR时忽略
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_TRANSMUX, TT_MP4_ADTS); // 传输类型，TT_MP4_ADIF/TT_MP4_ADTS/TT_MP4_LATM_MCP1...
	aacErrNum |= aacEncoder_SetParam(aacEncHandle, AACENC_AFTERBURNER, 1); 		// “加力燃烧室”，提高音质，0:关闭（默认） 1:开启。官方推荐内存和性能足够的话开启
	// 配置编码器 b/b：设置到编码器里面去
	aacErrNum |= aacEncEncode(aacEncHandle, NULL, NULL, NULL, NULL);
	if(aacErrNum != AACENC_OK)
	{
		DEBUG("Configure aac encoder error!\n");
		aacEncClose(&aacEncHandle);
		aacEncHandle = NULL;
		return -1;
	}

	/* AAC编码 3/8：获取编码器信息，从这里得到输入PCM缓存应该设置多大、输出最大的aac字节数 */
	aacErrNum = aacEncInfo(aacEncHandle, &aacEncInfoSt);
	if(aacErrNum != AACENC_OK)
	{
		DEBUG("Get aac encoder info error!\n");
		aacEncClose(&aacEncHandle);
		aacEncHandle = NULL;
		return -1;
	}

	// 根据上面获得的编码器信息得到一些比较重要的参数
	u32PcmInBufBytes = aacEncInfoSt.frameLength * u32PcmSampleBits/8 * u32PcmChannels;
	u32AacOutBufMaxBytes = aacEncInfoSt.maxOutBufBytes;
	frames_count = u32PcmInBufBytes/2;

	//DEBUG("PCM should in bytes: %d AAC out max bytes: %d\n", u32PcmInBufBytes, u32AacOutBufMaxBytes);

	/* 根据上面打开编码器信息分配对应大小的缓存 */
	pu8PcmInBuf  = (unsigned char*)malloc(u32PcmInBufBytes);
	pu8AacEncBuf = (unsigned char*)malloc(u32AacOutBufMaxBytes);

	/* aac编码一帧数据用到的参数 */
	inIdentifier = IN_AUDIO_DATA;
	outIdentifier = OUT_BITSTREAM_DATA;
	inElsize = sizeof(INT_PCM); // 参考aacenc_lib.h:260示例
	outElsize = sizeof(UCHAR);
	s32ReadPcmBytes = frames_count*2;

	/* AAC编码 5/8：填充编码器需要的参数，包括编码的pcm数据地址，大小等 */
	inPcmBufDesc.numBufs = 1;
	inPcmBufDesc.bufs = (void **)&pu8PcmInBuf;
	inPcmBufDesc.bufferIdentifiers = &inIdentifier;
	inPcmBufDesc.bufSizes = &s32ReadPcmBytes;
	inPcmBufDesc.bufElSizes = &inElsize;

	outAacBufDesc.numBufs = 1;
	outAacBufDesc.bufs = (void **)&pu8AacEncBuf;
	outAacBufDesc.bufferIdentifiers = &outIdentifier;
	outAacBufDesc.bufSizes = &u32AacOutBufMaxBytes;
	outAacBufDesc.bufElSizes = &outElsize;

	inArgs.numInSamples = s32ReadPcmBytes/2;

	DEBUG("aacEncEncode_init success\n");

	return 0;
}

void aacEncEncode_exit(void)
{
	/* 记得释放内存 */
	if(pu8PcmInBuf) free(pu8PcmInBuf);
	if(pu8AacEncBuf) free(pu8AacEncBuf);
	pu8AacEncBuf = NULL;
	pu8PcmInBuf = NULL;

	/* AAC编码 8/8：关闭编码器 */
	if(aacEncHandle) aacEncClose(&aacEncHandle);
	aacEncHandle = NULL;
}

static snd_pcm_t *alsa_record_open(unsigned int rate, unsigned int channels, snd_pcm_format_t format)
{
	int err;
	snd_pcm_t *pcm_handle;
	snd_pcm_hw_params_t *params; //此结构包含有关硬件的信息，可用于指定PCM流的配置

	int pcm;
	if ((err = snd_pcm_open (&pcm_handle, CARD_NAME, SND_PCM_STREAM_CAPTURE, 0)) < 0) 
	{
		DEBUG("snd_pcm_open error: %s (%s)\n",  CARD_NAME, snd_strerror (err));
		return NULL;
	}

    // 设置硬件参数
    snd_pcm_hw_params_malloc(&params);
    snd_pcm_hw_params_any(pcm_handle, params);
    snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(pcm_handle, params, format);
    snd_pcm_hw_params_set_channels(pcm_handle, params, channels);
    snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0);
    pcm = snd_pcm_hw_params(pcm_handle, params);
    if (pcm < 0) {
        DEBUG("ERROR: Can't set hardware parameters. %s\n", snd_strerror(pcm));
        return NULL;
    }
	DEBUG("alsa_record_open");

	return pcm_handle;
}

static void alsa_record_close(snd_pcm_t *handle)
{
	/*关闭音频采集卡硬件*/
	DEBUG("alsa_record_close");
	snd_pcm_close(handle);
}

void *audio_record_thread_handle(void *arg)
{
	int ret;
	int record_start_t = time(NULL);
	DEV_NODE * dev_node = NULL;

	dev_node = get_dev_node(g_devSn);

	hydrology_param_t hydrology_param;
	memset(&hydrology_param, 0, sizeof(hydrology_param));

	hydrology_param.cmdtype = HYD_CMD_RECORD;
	hydrology_param.buf = pu8AacEncBuf;
	if(dev_node) {
		memcpy(hydrology_param.dev_sn, dev_node->dev_sn, sizeof(dev_node->dev_sn));
		hydrology_param.addr = dev_node->devaddr;
	} else {
		hydrology_param.addr = 0;
	}

	//int fd;
	//fd = open("out_8khz_1ch.pcm", O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
	//清空数据
	//lseek(fd, 0, SEEK_SET);
	//ftruncate(fd, 0);

	if(record_thread_start == 0) {
		DEBUG("record_thread_start quit");
		pthread_exit(NULL);
		return NULL;
	}

	capture_handle = alsa_record_open(rate, channels, format);
	if(capture_handle == NULL) {
		pthread_exit(NULL);
		return NULL;
	}

	//最长60秒
	while(record_thread_start && (time(NULL) - record_start_t <= 60)) {
		ret = snd_pcm_readi(capture_handle, pu8PcmInBuf, frames_count);
		if(ret != frames_count) {
			  DEBUG("snd_pcm_readi err\n");
			  break;
		}

		/* AAC编码 6/8：将pcm编码出aac */
		aacErrNum = aacEncEncode(aacEncHandle, &inPcmBufDesc, &outAacBufDesc, &inArgs, &outArgs);
		if(aacErrNum != AACENC_OK) {
			DEBUG("Aac encoder encode error!\n");
		}

		DEBUG("outArgs.numOutBytes=%d", outArgs.numOutBytes);
		hydrology_param.length = outArgs.numOutBytes;
		hydrology_transform_enqueue(&hydrology_param);
	}

	alsa_record_close(capture_handle);

	DEBUG("record_thread exit");
	//close(fd);
	pthread_exit(NULL);
}

static int audio_start(void)
{
	if(audio_record_thread > 0) {
		record_thread_start = 0;
		DEBUG("audio_start pthread_ join");
		pthread_join(audio_record_thread, NULL);
		audio_record_thread = 0;
	}

	record_thread_start = 1;

	DEBUG("start record thread");	
	pthread_create(&audio_record_thread, NULL, audio_record_thread_handle, NULL);	//启动录音线程

	return 0;
}

static void audio_stop(void)
{
	if(audio_record_thread > 0) {
		record_thread_start = 0;
		DEBUG("audio_stop pthread_ join");
		pthread_join(audio_record_thread, NULL);
		audio_record_thread = 0;
	}
	DEBUG("record thread quit finish");	
}

void recordModuleInit(void)
{
	//myexec("amixer set Master 65536", NULL, NULL);
	//myexec("amixer set Capture 65536", NULL, NULL);
	aacEncEncode_init();
}

void recordWorkStart(char *devSN)
{
	if(devSN)
		strcpy(g_devSn, devSN);
	else
		memset(g_devSn, 0, sizeof(g_devSn));

	audio_start();
}

/**** ++++++ 语音广播 ++++++ ****/

//确认广播
void voice_broadcast_confirm(char *devSN)
{
	DEV_NODE * dev_node = NULL;
	hydrology_param_t hydrology_param;
	unsigned char buf[64];

	buf[0] = 0x01;
	buf[1] = 0x01;
	dev_node = get_dev_node(devSN);
	
	memset(&hydrology_param, 0, sizeof(hydrology_param));
	hydrology_param.cmdtype = HYD_CMD_RECORD_END;	//确认播报
	hydrology_param.buf = buf;
	hydrology_param.length = 2;
	if(dev_node) {
		memcpy(hydrology_param.dev_sn, dev_node->dev_sn, sizeof(dev_node->dev_sn));
		hydrology_param.addr = dev_node->devaddr;
	} else {
		hydrology_param.addr = 0;
	}

	hydrology_transform_enqueue(&hydrology_param);
}

//取消广播
void voice_broadcast_cancel(char *devSN)
{
	DEV_NODE * dev_node = NULL;
	hydrology_param_t hydrology_param;
	unsigned char buf[64];

	buf[0] = 0x02;
	buf[1] = 0x00;
	dev_node = get_dev_node(devSN);

	memset(&hydrology_param, 0, sizeof(hydrology_param));
	hydrology_param.cmdtype = HYD_CMD_RECORD_END;	//取消播报
	hydrology_param.buf = buf;
	hydrology_param.length = 2;
	if(dev_node) {
		memcpy(hydrology_param.dev_sn, dev_node->dev_sn, sizeof(dev_node->dev_sn));
		hydrology_param.addr = dev_node->devaddr;
	} else {
		hydrology_param.addr = 0;
	}

	hydrology_transform_enqueue(&hydrology_param);
}

/**** ------- ------- ------- ****/

void recordWorkStop(void)
{
	audio_stop();
}

static int voice_broadcast_thread_start = 0;
static int waring_level_value = 0;
static int waring_delay_value = 0;
static pthread_t voice_broadcast_threadid = 0;

static void *voice_broadcast_thread(void *arg)
{
	if(waring_delay_value > 0)
		second_sleep(waring_delay_value);

	//弹出qt注意安全界面
	trigger_alarm_notify_qt(waring_level_value);

	second_sleep(1);

	while(voice_broadcast_thread_start) {
		if(waring_level_value == 1) {
			//播报注意安全
			myexec("aplay /userdata/res/audio/be_careful.wav", NULL, NULL);
		}
		
		if(waring_level_value == 2) {
			//播报准备转移
			myexec("aplay /userdata/res/audio/prepare_transfer.wav", NULL, NULL);
		}
		
		if(waring_level_value == 3) {
			//播报立即转移
			myexec("aplay /userdata/res/audio/emerg_transfer.wav", NULL, NULL);
		}
	}

	pthread_exit(NULL);
}

void stop_voice_broadcast(void)
{
	DEBUG("stop_voice_broadcast");
	voice_broadcast_thread_start = 0;
	myexec("killall aplay", NULL, NULL);
}

void start_voice_broadcast(int waring_level, int waring_delay)
{
	DEBUG("start_voice broadcast");
	waring_level_value = waring_level;
	waring_delay_value = waring_delay;

	if(voice_broadcast_threadid > 0) {
		voice_broadcast_thread_start = 0;
		myexec("killall aplay", NULL, NULL);
		DEBUG("start_voice broadcast pthread_ join");
		pthread_cancel(voice_broadcast_threadid);
		pthread_join(voice_broadcast_threadid, NULL);
		voice_broadcast_threadid = 0;
	}

	voice_broadcast_thread_start = 1;
	pthread_create(&voice_broadcast_threadid, NULL, voice_broadcast_thread, NULL);
}

